﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Workflow;
using System.Globalization;

namespace AgileShare.Framework.Workflow.Helpers
{
    /// <summary>
    /// This class contains helper methods for working with SharePoint Workflows
    /// - All methods should be static
    /// - DO NOT USE SPContext
    /// </summary>
    public static class WorkflowHelper
    {
		public static string ApprovalWorkflowName = "Approval - SharePoint 2010";
		public static Guid WorkflowsFeatureId = new Guid("0af5989a-3aea-4519-8ab0-85d91abe39ff");

		/// <summary>
		/// Associates a Workflow to a List
		/// </summary>
		/// <param name="workflowTemplateName">The name of the workflow template.</param>
		/// <param name="workflowAssociationName">The name for the workflow association.</param>
		/// <param name="taskListTitle">The title of the task list for the workflow.</param>
		/// <param name="historyListTitle">The title of the history list for the workflow.</param>
		/// <param name="allowAsyncManualStart">True to enable Microsoft SharePoint Foundation to start the workflow asynchronously, even if the workflow was manually initiated.</param>
		/// <param name="allowManual">Sets whether workflow instances based on this workflow association can be started manually.</param>
		/// <param name="autoStartChange">True to have workflow instances based on this workflow associate start automatically when an item is changed.</param>
		/// <param name="autoStartCreate">True to have workflow instances based on this workflow associate start automatically when an item is created.</param>
		/// <param name="targetListTitle">The title of the list to associate the workflow with.</param>
		/// <param name="web">The web where the workflow template resides.</param>
		/// <returns>True if the association succeded, otherwise false.</returns>
		public static bool AssociateWorkflow(string workflowTemplateName, string workflowAssociationName, string targetListTitle, string taskListTitle, string historyListTitle, bool allowAsyncManualStart, bool allowManual, bool autoStartChange, bool autoStartCreate, string associationData, SPWeb web)
		{
			bool success = false;

			SPList historyList = web.Lists.TryGetList(historyListTitle);
			SPList taskList = web.Lists.TryGetList(taskListTitle);
			SPList targetList = web.Lists.TryGetList(targetListTitle);

			if (historyList != null && taskList != null)
			{
				success = AssociateWorkflow(workflowTemplateName, workflowAssociationName, targetList, taskList, historyList, allowAsyncManualStart, allowManual, autoStartChange, autoStartCreate, associationData, web);
			}

			return success;
		}

		/// <summary>
		/// Associates a Workflow Template to a List, using the default workflow history list
		/// </summary>
		/// <param name="workflowTemplateName">The name of the workflow template.</param>
		/// <param name="workflowAssociationName">The name for the workflow association.</param>
		/// <param name="taskList">The task list for the workflow.</param>		
		/// <param name="allowAsyncManualStart">True to enable Microsoft SharePoint Foundation to start the workflow asynchronously, even if the workflow was manually initiated.</param>
		/// <param name="allowManual">Sets whether workflow instances based on this workflow association can be started manually.</param>
		/// <param name="autoStartChange">True to have workflow instances based on this workflow associate start automatically when an item is changed.</param>
		/// <param name="autoStartCreate">True to have workflow instances based on this workflow associate start automatically when an item is created.</param>
		/// <param name="targetList">The list to associate the workflow with.</param>
		/// <param name="web">The web where the workflow template resides.</param>
		/// <returns>True if the association succeded, otherwise false.</returns>
		public static bool AssociateWorkflow(string workflowTemplateName, string workflowAssociationName, SPList targetList, SPList taskList, bool allowAsyncManualStart, bool allowManual, bool autoStartChange, bool autoStartCreate, string associationData, SPWeb web)
		{
			SPList historyList = EnsureDefaultHistoryList(web);
			return AssociateWorkflow(workflowTemplateName, workflowAssociationName, targetList, taskList, historyList, allowAsyncManualStart, allowManual, autoStartChange, autoStartCreate, associationData, web);
		}

		/// <summary>
		/// Associates a Workflow Template to a List
		/// </summary>
		/// <param name="workflowTemplateName">The name of the workflow template.</param>
		/// <param name="workflowAssociationName">The name for the workflow association.</param>
		/// <param name="taskList">The task list for the workflow.</param>
		/// <param name="historyList">The history list for the workflow.</param>
		/// <param name="allowAsyncManualStart">True to enable Microsoft SharePoint Foundation to start the workflow asynchronously, even if the workflow was manually initiated.</param>
		/// <param name="allowManual">Sets whether workflow instances based on this workflow association can be started manually.</param>
		/// <param name="autoStartChange">True to have workflow instances based on this workflow associate start automatically when an item is changed.</param>
		/// <param name="autoStartCreate">True to have workflow instances based on this workflow associate start automatically when an item is created.</param>
		/// <param name="targetList">The list to associate the workflow with.</param>
		/// <param name="web">The web where the workflow template resides.</param>
		/// <returns>True if the association succeded, otherwise false.</returns>
		public static bool AssociateWorkflow(string workflowTemplateName, string workflowAssociationName, SPList targetList, SPList taskList, SPList historyList, bool allowAsyncManualStart, bool allowManual, bool autoStartChange, bool autoStartCreate, string associationData, SPWeb web)
		{
			bool success = false;

			SPWorkflowTemplate workflowTemplate = web.WorkflowTemplates.GetTemplateByName(workflowTemplateName, web.Locale);

			if (workflowTemplate != null)
			{
				if (targetList != null)
				{
					SPWorkflowAssociation workflowAssociation = targetList.WorkflowAssociations.GetAssociationByName(workflowAssociationName, CultureInfo.InvariantCulture);
					if (workflowAssociation == null)
					{
						workflowAssociation = CreateWorkflowListAssociation(workflowTemplate, workflowAssociationName, taskList, historyList, allowAsyncManualStart, allowManual, autoStartChange, autoStartCreate, associationData);
						targetList.WorkflowAssociations.Add(workflowAssociation);
						workflowAssociation.Enabled = true;
					}
					success = true;
				}
			}
			return success;
		}

		/// <summary>
		/// Deassociates a Workflow Template from a List.
		/// </summary>
		/// <param name="workflowAssociationName">The name of the workflow.</param>
		/// <param name="targetListTitle">The title of the list to deassociate the workflow from.</param>
		/// <param name="web">The web where the list resides.</param>
		public static void DeassociateWorkflow(string workflowAssociationName, string targetListTitle, SPWeb web)
		{
			SPList list = web.Lists.TryGetList(targetListTitle);
			if (list != null)
			{
				DeassociateWorkflow(workflowAssociationName, list);
			}
		}

		/// <summary>
		/// Deassociates a Workflow Template from a List.
		/// </summary>
		/// <param name="workflowAssociationName">The name of the workflow.</param>
		/// <param name="list">The list to deasocciate the workflow from.</param>
		public static void DeassociateWorkflow(string workflowAssociationName, SPList list)
		{
			if (list != null)
			{
				SPWorkflowAssociation association = list.WorkflowAssociations.GetAssociationByName(workflowAssociationName, System.Globalization.CultureInfo.InvariantCulture);
				if (association != null)
				{
					list.WorkflowAssociations.Remove(association);
				}
			}
		}

		/// <summary>
		/// Creates an association to a workflow template that can be used to associate a list with a workflow.
		/// </summary>
		/// <param name="workflowTemplate">The Workflow Template object for the Workflow Association.</param>		
		/// <param name="workflowAssociationName">The name for the workflow association.</param>
		/// <param name="taskList">The task list for the workflow.</param>
		/// <param name="historyList">The history list for the workflow.</param>
		/// <param name="allowAsyncManualStart">True to enable Microsoft SharePoint Foundation to start the workflow asynchronously, even if the workflow was manually initiated.</param>
		/// <param name="allowManual">Sets whether workflow instances based on this workflow association can be started manually.</param>
		/// <param name="autoStartChange">True to have workflow instances based on this workflow associate start automatically when an item is changed.</param>
		/// <param name="autoStartCreate">True to have workflow instances based on this workflow associate start automatically when an item is created.</param>
		/// <returns></returns>
		public static SPWorkflowAssociation CreateWorkflowListAssociation(SPWorkflowTemplate workflowTemplate, string workflowAssociationName, SPList taskList, SPList historyList, bool allowAsyncManualStart, bool allowManual, bool autoStartChange, bool autoStartCreate, string associationData)
		{
			SPWorkflowAssociation workflowAssociation = SPWorkflowAssociation.CreateListAssociation(workflowTemplate, workflowAssociationName, taskList, historyList);
			workflowAssociation.AllowAsyncManualStart = allowAsyncManualStart;
			workflowAssociation.AllowManual = allowManual;
			workflowAssociation.AutoStartChange = autoStartChange;
			workflowAssociation.AutoStartCreate = autoStartCreate;
			workflowAssociation.AssociationData = associationData ?? "";

			return workflowAssociation;
		}

		public static void StartWorkflow(SPListItem listItem, string workflowAssociationName)
		{
			SPWorkflowAssociation workflowAssociation = listItem.ParentList.WorkflowAssociations.GetAssociationByName(workflowAssociationName, CultureInfo.InvariantCulture);
			if (workflowAssociation != null)
			{
				SPWorkflowManager workflowManager = listItem.ParentList.ParentWeb.Site.WorkflowManager;
				workflowManager.StartWorkflow(listItem, workflowAssociation, workflowAssociation.AssociationData);
			}
		}

		public static SPList EnsureDefaultHistoryList(SPWeb web)
		{
			string historyListName = SPResource.GetString("DefaultWorkflowHistoryListName", new object[0]);
			SPList historyList = web.Lists.TryGetList(historyListName);
			if (historyList != null)
			{
				return historyList;
			}
			// create list if there is no such list yet
			Guid listGuid = web.Lists.Add(historyListName, string.Empty, SPListTemplateType.WorkflowHistory);
			historyList = web.Lists.GetList(listGuid, false);
			historyList.Hidden = true;
			historyList.Update();
			return historyList;
		}
    }
}
